package com.dlc.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.app.dto.SkuDto;
import com.dlc.shop.bean.app.vo.SkuVO;
import com.dlc.shop.bean.dto.StockPointSkuDTO;
import com.dlc.shop.bean.enums.ProdMoldEnum;
import com.dlc.shop.bean.enums.ProdStatusEnums;
import com.dlc.shop.bean.enums.StockBillType;
import com.dlc.shop.bean.enums.StockType;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.param.ProductParam;
import com.dlc.shop.bean.vo.*;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.constants.CacheNames;
import com.dlc.shop.common.constants.StockPointType;
import com.dlc.shop.common.enums.StatusEnum;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.i18n.I18nMessage;
import com.dlc.shop.common.util.*;
import com.dlc.shop.dao.SkuLangMapper;
import com.dlc.shop.dao.SkuMapper;
import com.dlc.shop.manager.impl.LangManager;
import com.dlc.shop.manager.impl.StockManager;
import com.dlc.shop.service.*;
import com.dlc.shop.util.StockUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.ibatis.annotations.Param;
import org.apache.poi.ss.usermodel.Sheet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author lgh on 2018/09/29.
 */
@Slf4j
@Service
@AllArgsConstructor
public class SkuServiceImpl extends ServiceImpl<SkuMapper, Sku> implements SkuService {

    private final Logger logger = LoggerFactory.getLogger(SkuServiceImpl.class);
    private final SkuMapper skuMapper;
    private final SkuLangMapper skuLangMapper;
    private final SkuLangService skuLangService;
    private final SkuComboService skuComboService;
    private final SkuStockService skuStockService;
    private final LangManager langManager;
    private final StockPointSkuService stockPointSkuService;
    private final WarehouseService warehouseService;
    private final StockManager stockManager;


    private final static String[] SKU_EXPORT_COL = {
            I18nMessage.getMessage("yami.sku.excel.header.code"),
            I18nMessage.getMessage("yami.sku.excel.header.name"),
            I18nMessage.getMessage("yami.sku.excel.header.spec"),
            I18nMessage.getMessage("yami.sku.excel.header.stock"),
            I18nMessage.getMessage("yami.sku.excel.header.price")
    };

    @Override
    @Cacheable(cacheNames = CacheNames.SKU_LIST_KEY, key = "#prodId")
    public List<Sku> listSkuByProdId(Long prodId) {
        List<Sku> skuList = skuMapper.listByProdId(prodId);
        langManager.getSkuAndLang(skuList);
        if (CollectionUtils.isEmpty(skuList)) {
            return null;
        }
        return skuList;
    }

    @Override
    public List<Sku> listSkuAndSkuNameByProdId(Long prodId) {
        SkuServiceImpl skuService = (SkuServiceImpl) AopContext.currentProxy();
        List<Sku> skuList = skuService.listSkuByProdId(prodId);
        langManager.handleSkuLang(skuList);
        return skuList;
    }

    @Override
    public List<Sku> listSkuAndSkuStock(Long prodId, Integer mold) {
        List<Sku> skuList = this.listSkuAndSkuStockAndLang(prodId, mold);
        if (CollectionUtils.isEmpty(skuList)) {
            logger.info("商品不存在或已被删除，返回空");
            return null;
        }
        for (Sku sku : skuList) {
            sku.setSkuLangList(null);
        }
        return skuList;
    }

    @Override
    public List<Sku> listSkuAndSkuStockAndLang(Long prodId, Integer mold) {
        SkuServiceImpl skuService = (SkuServiceImpl) AopContext.currentProxy();
        List<Sku> skuList = skuService.listSkuByProdId(prodId);
        for (Sku sku : skuList) {
            sku.setMold(mold);
        }
        if (CollUtil.isEmpty(skuList)) {
            return skuList;
        }
        // List<SkuStock> skuStocks = skuStockService.listSkuStockByProdId(prodId);
        setSkuStock(skuList);

//        Map<Long, SkuStock> skuStockMap = skuStocks.stream().collect(Collectors.toMap(SkuStock::getSkuId, s -> s));
//        for (Sku sku : skuList) {
//            if (!skuStockMap.containsKey(sku.getSkuId())) {
//                continue;
//            }
//            // 插入库存信息
//            SkuStock skuStock = skuStockMap.get(sku.getSkuId());
//            sku.setStocks(skuStock.getStocks());
//            sku.setActualStock(skuStock.getActualStock());
//        }
        langManager.handleSkuAndLang(skuList);
        // 如果是组合商品获取所有组合的商品信息并组装,然后计算出对应库存
        if (Objects.equals(mold, ProdMoldEnum.COMBO.value())) {
            assembleComboSpuListAndStock(skuList);
        }
        return skuList;
    }

    @Override
    public List<Sku> listPutOnSkuAndSkuStock(Long prodId, Integer mold) {
        List<Sku> skus = listSkuAndSkuStock(prodId, mold);
        if (Objects.isNull(skus)) {
            return new ArrayList<>();
        }
        // 这个接口都是用户端在用，不需要返回完整的国际化信息
        for (Sku sku : skus) {
            sku.setSkuLangList(null);
        }
        return skus.stream().filter(sku -> Objects.equals(sku.getStatus(), StatusEnum.ENABLE.value())).collect(Collectors.toList());
    }

    @Override
    @Cacheable(cacheNames = CacheNames.SKU_KEY, key = "#skuId", unless ="#result == null" )
    public Sku getSkuBySkuId(Long skuId) {
        Sku sku = skuMapper.getSkuBySkuId(skuId);
        langManager.getSkuAndLang(sku);
        List<StockPointSkuVO> stockPointSkuList = stockPointSkuService.listPointBySkuIds(Collections.singletonList(skuId));
        stockPointSkuList.sort(Comparator.comparing(StockPointSkuVO::getType));
        sku.setStockPointList(BeanUtil.mapAsList(stockPointSkuList, StockPointSkuDTO.class));
        return sku;
    }

    @Override
    public Sku getSkuAndName(Long skuId) {
        SkuServiceImpl skuService = (SkuServiceImpl) AopContext.currentProxy();
        Sku sku = skuService.getSkuBySkuId(skuId);
        if (Objects.isNull(sku)) {
            return sku;
        }
        langManager.handleSkuAndLang(sku);
        this.setSkuStock(Collections.singletonList(sku));
        return sku;
    }

    @Override
    public Sku getSkuListBySkuId(Long skuId) {
        Sku sku = skuMapper.getSkuBySkuId(skuId);
        langManager.getSkuAndLang(sku);
        setSkuStock(Collections.singletonList(sku));
        return sku;
    }

    @Override
    public void removeSkuCacheBySkuId(Long skuId, Long prodId) {
        List<String> keys = new ArrayList<>();
        // cacheNames = "sku"
        keys.add(CacheNames.SKU_KEY + CacheNames.UNION + skuId);
        // cacheNames = "skuList"
        keys.add(CacheNames.SKU_LIST_KEY + CacheNames.UNION + prodId);
        keys.add(CacheNames.SKU_LIST_KEY + CacheNames.UNION + prodId);
        // cacheNames = "listSkuStockByProdId",
        keys.add(CacheNames.LIST_SKU_STOCK_KEY + CacheNames.UNION + prodId);
        RedisUtil.del(keys);
    }

    @Override
    public void removeSkuStockCache(Long skuId, Long prodId) {
        List<String> keys = new ArrayList<>();
        // cacheNames = "sku"
        keys.add(CacheNames.SKU_KEY + CacheNames.UNION + skuId);
        // cacheNames = "listSkuStockByProdId",
        keys.add(CacheNames.LIST_SKU_STOCK_KEY + CacheNames.UNION + prodId);
        RedisUtil.del(keys);
    }

    @Override
    public void batchRemoveSkuStockCache(Map<Long, Long> skuMap) {
        if (MapUtil.isEmpty(skuMap)) {
            return;
        }
        List<String> keys = new ArrayList<>();
        for (Map.Entry<Long, Long> entry : skuMap.entrySet()) {
            // cacheNames = "sku"
            keys.add(CacheNames.SKU_KEY + CacheNames.UNION + entry.getKey());
            Long prodId = entry.getValue();
            // cacheNames = "skuList"
            keys.add(CacheNames.SKU_LIST_KEY + CacheNames.UNION + prodId);
            keys.add(CacheNames.SKU_LIST_KEY + CacheNames.UNION + prodId);
            // cacheNames = "listSkuStockByProdId",
            keys.add(CacheNames.LIST_SKU_STOCK_KEY + CacheNames.UNION + prodId);
        }
        RedisUtil.del(keys);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSku(Sku sku, Integer mold) {
        // 移除空字符串
        if (Objects.nonNull(sku) && StrUtil.isBlank(sku.getPic())) {
            sku.setPic(null);
        }
        sku.setUpdateTime(new Date());
        Integer changeStock = sku.getChangeStock();
        // 设置库存为null, 不更新库存
        Integer tempStock = sku.getStocks();
        // 更新sku,该方法不更新库存
        skuMapper.updateSkuById(sku);
        skuLangMapper.batchUpdateBySkuIdAndLang(sku.getSkuLangList());
//        // 通过变化库存数更新库存
//        if (Objects.nonNull(changeStock)) {
//            Sku temp = getSkuAndStock(sku.getSkuId());
//            if (changeStock != 0) {
////                if (tempStock - changeStock != temp.getStocks()) {
////                    throw new YamiShopBindException("yami.product.sku.invalid");
////                }
//                skuStockService.updateSkuStocks(sku.getSkuId(), changeStock);
//            }
////            else {
////                if (!Objects.equals(temp.getStocks(), tempStock)) {
////                    throw new YamiShopBindException("yami.product.sku.invalid");
////                }
////            }
//        }
        // 如果是组合商品,更新组合商品关联信息
        if (!Objects.equals(mold, ProdMoldEnum.COMBO.value())) {
            return;
        }
        skuComboService.remove(new LambdaQueryWrapper<SkuCombo>().eq(SkuCombo::getSkuId, sku.getSkuId()));
        List<SkuCombo> skuComboList = BeanUtil.mapAsList(sku.getSkuComboList(), SkuCombo.class);
        skuComboList.forEach(skuCombo -> skuCombo.setSkuId(sku.getSkuId()));
        if (CollectionUtil.isNotEmpty(skuComboList)) {
            skuComboService.saveBatch(skuComboList);
        }
    }

    @Override
    public List<SkuStockVO> insertBatchAndLang(List<Sku> skuList, Long shopId, Integer mold, Integer spuStatus, String mobile, Long employeeId) {
        // 移除空字符串
        for (Sku sku : skuList) {
            if (StrUtil.isBlank(sku.getPic()) && Objects.nonNull(sku)) {
                sku.setPic(null);
            }
        }
        skuMapper.insertBatchReturnId(skuList);
        // 保存语言表
        saveSkuLang(skuList);
        // 保存sku库存
        // saveSkuStocks(skuList);
        // 如果是组合商品,保存关联信息
        if (Objects.equals(mold, ProdMoldEnum.COMBO.value())) {
            // 保存组合商品关联信息
            saveSkuCombo(skuList);
        }
        return saveSkuStocks(skuList, shopId, mold, spuStatus, employeeId, mobile);

    }

    /**
     * 保存sku库存信息
     *
     * @param skuList
     */
    private List<SkuStockVO> saveSkuStocks(List<Sku> skuList, Long shopId, Integer spuMold, Integer spuStatus, Long employeeId, String mobile) {
        Long prodId = skuList.get(0).getProdId();
        Integer sysType = SysTypeEnum.MULTISHOP.value();
        if (Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
            sysType = SysTypeEnum.PLATFORM.value();
        }
        List<SkuStockVO> skuStocks = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<StockPointSkuDTO> stockPointS = new ArrayList<>(Constant.INITIAL_CAPACITY);
        WarehouseVO warehouse = warehouseService.getDefaultWarehouseByShopId(shopId, sysType);
        if (Objects.isNull(warehouse)) {
            throw new YamiShopBindException("yami.warehouse.default.null");
        }
        for (Sku sku : skuList) {
            // 添加库存
            addStockPoint(spuMold, stockPointS, prodId, spuStatus, skuStocks, sku, warehouse.getWarehouseId());
            // TODO 组合商品判断
//            if(Objects.equals(spuMold, ProdMoldEnum.COMBO.value())){
//                addCombo(skuComboList, skuDTO);
//            }
        }
        stockPointSkuService.batchSave(stockPointS);
        for (Sku sku : skuList) {
            sku.setChangeStock(sku.getStocks());
        }
        // 平台发布的积分商品，没有出入库详情
        if (shopId != Constant.PLATFORM_SHOP_ID && !Objects.equals(spuMold, ProdMoldEnum.COMBO.value())) {
            // 入库初始化库存
            skuStockService.addBillLogList(employeeId, mobile, sysType, StockBillType.INITIALIZE.value(), StockType.WAREHOUSING.value(), stockPointS, skuList, shopId, null);
        }
        // TODO 保存修改一下组合商品关联
//        if(CollectionUtil.isNotEmpty(skuComboList)){
//            skuComboService.saveBatch(skuComboList);
//        }
        batchUpdateSkuWarning(skuList);
        return skuStocks;
    }

    @Override
    public List<String> listSkuByProdIds(List<Long> prodIds, Long disProdId) {
        if (CollectionUtils.isNotEmpty(prodIds)) {
            return skuMapper.listSkuPartyCodeByProdIds(prodIds, disProdId);
        }
        return new ArrayList<>();
    }

    @Override
    public List<Sku> listSkuAndLangByProdIds(List<Long> prodIds) {
        List<Sku> skuList = skuMapper.listSkuAndLangByProdIds(prodIds);
        langManager.handleSkuAndLang(skuList);
        // 插入库存
        setSkuStock(skuList);
        return skuList;
    }

    @Override
    public Sku getSkuByShopIdAndPartyCode(Long shopId, String partyCode) {
        Sku sku = skuMapper.getSkuByPartyCode(shopId, partyCode);
        if (Objects.isNull(sku)) {
            return null;
        }
        setSkuStock(Collections.singletonList(sku));
        langManager.getProdNameToSku(sku);
        return sku;
    }

    @Override
    public IPage<StockBillLogItem> inquireStock(PageParam<StockBillLog> page, ProductParam productParam) {
        IPage<StockBillLogItem> stockBillLogItemPage = skuMapper.inquireStock(page, productParam);
        List<Long> skuIds = stockBillLogItemPage.getRecords().stream().map(StockBillLogItem::getSkuId).toList();
        Map<Long, SkuStockVO> skuStockMap = skuStockService.mapSkuTotalStock(skuIds);
        for (StockBillLogItem stockBillLogItem : stockBillLogItemPage.getRecords()) {
            SkuStockVO skuStockVO = skuStockMap.get(stockBillLogItem.getSkuId());
            stockBillLogItem.setStocks(skuStockVO.getStock());
        }
        langManager.getStockBillLogItem(stockBillLogItemPage.getRecords());
        return stockBillLogItemPage;
    }

    @Override
    public void exportSkuList(ProductParam product, HttpServletResponse response) {
        List<Sku> skuList = skuMapper.listExportSku(product);
        if (CollUtil.isEmpty(skuList)) {
            return;
        }
        List<Long> skuIds = skuList.stream().map(Sku::getSkuId).collect(Collectors.toList());
        Map<Long, SkuStockVO> stockMap = stockManager.mapSkuTotalStock(skuIds);
        skuList.forEach(s -> s.setStocks(stockMap.get(s.getSkuId()).getStock()));
        langManager.getSkuAndLang(skuList);
        ExcelWriter writer = ExcelUtil.getBigWriter();
        final List<String> exportCol = Arrays.asList(SKU_EXPORT_COL);
        // 最大列数量
        int maxColNum = exportCol.size();

        Sheet sheet = writer.getSheet();
        // 设置列宽
        this.setColumnWidth(sheet);
        // 标题
        writer.merge(maxColNum - 1, I18nMessage.getMessage("yami.sku.excel.title"));
        // 列名
        writer.writeRow(exportCol);
        int rowIndex = 2;
        for (Sku sku : skuList) {
            int col = -1;
            // 商品编码
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, sku.getPartyCode());
            // 商品名称
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, sku.getProdName());
            // 规格
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, sku.getSkuName());
            // 商品库存
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, sku.getStocks());
            // 商品价格
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, sku.getPrice());

            ++rowIndex;
        }
        PoiExcelUtil.writeExcel(response, writer);
    }

    @Override
    public List<SkuDto> getProdDetailSkuInfo(Product product) {
        List<Sku> skuList = skuMapper.getProdDetailSkuInfo(product.getProdId());
        if (CollUtil.isEmpty(skuList)) {
            return new ArrayList<>();
        }
        langManager.getSkuLang(skuList);
        if (Objects.equals(product.getMold(), ProdMoldEnum.COMBO.value())) {
            assembleComboSpuListAndStock(skuList);
        } else {
            this.setSkuStock(skuList);
        }
        return BeanUtil.mapAsList(skuList, SkuDto.class);
    }

    private void setColumnWidth(Sheet sheet) {
        int index = -1;
        // 商品编码
        sheet.setColumnWidth(++index, 50 * 256);
        // 商品名称
        sheet.setColumnWidth(++index, 80 * 256);
        // 规格
        sheet.setColumnWidth(++index, 50 * 256);
        // 商品库存
        sheet.setColumnWidth(++index, 20 * 256);
        // 商品价格
        sheet.setColumnWidth(++index, 20 * 256);
    }

    @Override
    public IPage<Sku> pageSku(PageParam<Sku> page, ProductParam product) {
        IPage<Sku> skuPage = skuMapper.pageSku(page, product);
        langManager.getSkuLang(skuPage.getRecords());
        // 插入库存
        setSkuStock(skuPage.getRecords());
        skuPage.getRecords().forEach(sku -> sku.setDeliveryModeVO(Json.parseObject(sku.getDeliveryMode(), Product.DeliveryModeVO.class)));
        return skuPage;
    }

    private void saveSkuLang(List<Sku> skuList) {
        List<SkuLang> skuLangList = new ArrayList<>();
        for (Sku sku : skuList) {
            checkProdLang(sku.getSkuLangList());
            for (SkuLang skuLang : sku.getSkuLangList()) {
                skuLang.setSkuId(sku.getSkuId());
            }
            skuLangList.addAll(sku.getSkuLangList());
        }
        skuLangService.saveBatch(skuLangList);
    }

    private void checkProdLang(List<SkuLang> skuLangList) {
        Integer lang = langManager.getDefaultLang();
        boolean containsMaster = false;
        for (SkuLang skuLang : skuLangList) {
            if (Objects.equals(skuLang.getLang(), lang)) {
                containsMaster = true;
            }
        }
        if (!containsMaster) {
            throw new YamiShopBindException("语言数据已更新，请重新录入商品信息");
        }
    }

    @Override
    public List<Sku> listSkuBySkuIds(List<Long> skuIds) {
        if (CollUtil.isEmpty(skuIds)) {
            return new ArrayList<>();
        }
        return skuMapper.listSkuBySkuIds(skuIds);
    }

    @Override
    public Long stockWarningCount(Long shopId) {
        List<Sku> skus = skuMapper.stockWarningCount(shopId);
        setSkuStock(skus);
        long count = skus.stream().filter(sku -> Objects.nonNull(sku.getStockWarning()) && sku.getStocks() <= sku.getStockWarning()).count();
        return count;
    }

    @Override
    public List<SkuVO> listSkuWithLang(SkuDto skuDto) {
        return skuMapper.listSkuWithLang(skuDto);
    }

    private void saveSkuCombo(List<Sku> skuList) {
        List<SkuCombo> skuCombos = new ArrayList<>();
        for (Sku sku : skuList) {
            if (CollUtil.isEmpty(sku.getSkuComboList())) {
                continue;
            }
            List<SkuCombo> skuComboList = BeanUtil.mapAsList(sku.getSkuComboList(), SkuCombo.class);
            skuComboList.forEach(skuCombo -> skuCombo.setSkuId(sku.getSkuId()));
            skuCombos.addAll(skuComboList);
        }
        skuComboService.saveBatch(skuCombos);
    }

    @Override
    public void assembleComboSpuListAndStock(List<Sku> skuList) {
        List<Long> skuIds = skuList.stream().map(Sku::getSkuId).toList();
        skuList.forEach(sku -> sku.setStocks(0));
        List<SkuComboVO> totalSkuComboList = skuComboService.listCombSpuBySkuIds(skuIds);
        if (CollUtil.isEmpty(totalSkuComboList)) {
            return;
        }
        // 获取所有组合的商品库存
        List<Long> comboSkuIds = totalSkuComboList.stream().map(SkuComboVO::getComboSkuId).toList();
        if (CollectionUtil.isEmpty(comboSkuIds)) {
            return;
        }
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(comboSkuIds);
        // 获取sku区域库存
        Map<String, SkuStockVO> stockMap = skuStockService.mapSkuTotalStockAndPointStock(stockPointList);
        // 只需要计算仓库的库存
        // 设置一下组合的商品库存
        Map<Long, List<SkuComboVO>> skuComboMap = totalSkuComboList.stream().collect(Collectors.groupingBy(SkuComboVO::getSkuId));
        Map<Long, List<StockPointSkuVO>> skuPoinStockMap = stockPointList.stream().collect(Collectors.groupingBy(StockPointSkuVO::getStockPointId));
        // 根据主组合商品的skuId组成map
        for (Sku sku : skuList) {
            sku.setStocks(0);
            long skuId = sku.getSkuId();
            // 当前sku关联的组合单品列表
            Map<Long, Integer> pointStockMap = new HashMap<>(skuPoinStockMap.size());
            List<SkuComboVO> skuComboList = skuComboMap.get(skuId);
            if (CollectionUtil.isEmpty(skuComboList)) {
                continue;
            }
            // 获取每个区域单品的最小组合库存数量
            for (Map.Entry<Long, List<StockPointSkuVO>> entry : skuPoinStockMap.entrySet()) {
                // 跳过总库存
                if (entry.getKey() == 0) {
                    continue;
                }
                List<StockPointSkuVO> stockPointSkus = entry.getValue();
                // 如果当前仓库的所有sku库存为空,或者小于需要查询的sku的数量,表示这些关联的sku没有共同库存跳过即可
                if (CollUtil.isEmpty(stockPointSkus) || stockPointSkus.size() < skuComboList.size()) {
                    continue;
                }
                Map<Long, StockPointSkuVO> comboSkuPoinStockMap = stockPointSkus.stream().collect(Collectors.toMap(StockPointSkuVO::getSkuId, Function.identity()));
                // 计算区域中的单品的最小库存数量
                for (SkuComboVO skuComboVO : skuComboList) {
                    StockPointSkuVO stockPointSkuVO = comboSkuPoinStockMap.get(skuComboVO.getComboSkuId());
                    if (Objects.isNull(stockPointSkuVO)) {
                        continue;
                    }
                    // 计算sku中每个单品的库存数量
                    // 获取单品的区域库存信息
                    SkuStockVO skuStockVO = stockMap.get(StockUtil.skuPointKey(skuComboVO.getComboSkuId(), stockPointSkuVO.getStockPointId()));
                    // 组合sku中单品实际库存数量 = 单品库存数量 / 单品组合数量
                    // 除以组合数量向下取整得出 当前的组合商品-当前仓库 可用库存
                    int pointStock = Math.floorDiv(skuStockVO.getStock(), skuComboVO.getComboCount());
                    // 如果是0就是总库存,直接跳过
                    if (Objects.equals(stockPointSkuVO.getStockPointId(), StockManager.WAREHOUSE_ID)) {
                        continue;
                    }
                    // 组合商品的库存取最小值,比如都是默认仓库的情况下,取最小值
                    if (!pointStockMap.containsKey(stockPointSkuVO.getStockPointId()) || pointStockMap.get(stockPointSkuVO.getStockPointId()) > pointStock) {
                        pointStockMap.put(stockPointSkuVO.getStockPointId(), pointStock);
                    }
                }
            }
            // 单品的总库存
            for (SkuComboVO skuComboVO : skuComboList) {
                skuComboVO.setStock(stockMap.get(skuComboVO.getComboSkuId().toString()).getStock());
            }
            // 累加上sku的所有组合商品的所有仓库的库存最小值,就是当前sku可用的最小库存
            int totalStock = 0;
            for (Long pointId : pointStockMap.keySet()) {
                totalStock += pointStockMap.get(pointId);
            }
            sku.setStocks(totalStock);
            sku.setSkuComboList(skuComboList);
//            List<Long> skuList = skuComboList.stream().map(SkuComboVO::getComboSkuId).collect(Collectors.toList());
//            if (!hasStockBySkuIds(skuList, shopId)) {
//                sku.setStock(0);
//            }
        }
    }

    @Override
    public List<SkuVO> listSkuAndStockByStockPointId(Long stockPointId, Long inStockPointId, Integer queryHasStock) {
        List<StockPointSkuVO> pointSkuList = stockPointSkuService.listByPointId(stockPointId);
        if (CollectionUtil.isEmpty(pointSkuList)) {
            return new ArrayList<>();
        }
        List<Long> skuIds = pointSkuList.stream().map(StockPointSkuVO::getSkuId).collect(Collectors.toList());
        // 获取sku信息列表
        SkuDto skuDto = new SkuDto();
        skuDto.setSkuIds(skuIds);
        List<SkuVO> skuList = BeanUtil.mapAsList(skuMapper.listSkuWithLang(skuDto), SkuVO.class);
        // 获取库存信息集合
        boolean fillInStockPointStock = !Objects.isNull(inStockPointId);
        if (fillInStockPointStock) {
            for (Long skuId : skuIds) {
                pointSkuList.add(new StockPointSkuVO(skuId, inStockPointId));
            }
        }
        Map<String, SkuStockVO> skuStockVOMap = skuStockService.mapSkuTotalStockAndPointStock(pointSkuList);
        // 设置sku库存
        boolean isHasStock = Objects.equals(queryHasStock, 1);
        List<SkuVO> hasStockSkus = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (SkuVO skuVO : skuList) {
            SkuStockVO skuStockVO = skuStockVOMap.get(StockUtil.skuPointKey(skuVO.getSkuId(), stockPointId));
            skuVO.setStocks(skuStockVO.getStock());
            if (fillInStockPointStock) {
                // 补充入库点该sku库存
                SkuStockVO skuPointStockVO = skuStockVOMap.get(StockUtil.skuPointKey(skuVO.getSkuId(), inStockPointId));
                skuVO.setInStockPointStock(Objects.isNull(skuPointStockVO) ? 0 : skuPointStockVO.getStock());
            }
            if (isHasStock && !Objects.equals(skuVO.getStocks(), 0)) {
                hasStockSkus.add(skuVO);
            }
        }
        return isHasStock ? hasStockSkus : skuList;
    }

    @Override
    public void addStockPoint(Integer spuMold, List<StockPointSkuDTO> stockPointS, Long prodId, Integer spuStatus, List<SkuStockVO> skuStocks, Sku skuDTO, Long defaultWarehouseId) {
        Integer status = StatusEnum.DISABLE.value();
        if (Objects.equals(spuStatus, ProdStatusEnums.NORMAL.getValue()) && Objects.equals(skuDTO.getStatus(), StatusEnum.ENABLE.value())) {
            status = StatusEnum.ENABLE.value();
        }
        // 如果是组合商品,添加一条默认仓库库存为0的数据
        if (Objects.equals(spuMold, ProdMoldEnum.COMBO.value())) {
            SkuStockVO skuStock = new SkuStockVO(skuDTO.getSkuId(), skuDTO.getStocks(), defaultWarehouseId, StockPointType.WAREHOUSE.getValue());
            skuStock.setProdId(prodId);
            skuStock.setLockStock(0);
            skuStock.setStatus(status);
            skuStocks.add(skuStock);
        } else {
            for (StockPointSkuDTO stockPointSkuDTO : skuDTO.getStockPointList()) {
                stockPointSkuDTO.setSkuId(skuDTO.getSkuId());
                stockPointSkuDTO.setStatus(skuDTO.getStatus());
                stockPointSkuDTO.setProdId(prodId);
                stockPointS.add(stockPointSkuDTO);
                SkuStockVO skuStock = new SkuStockVO(stockPointSkuDTO.getSkuId(), stockPointSkuDTO.getStock(), stockPointSkuDTO.getStockPointId(), stockPointSkuDTO.getStockPointType());
                skuStock.setProdId(prodId);
                skuStock.setLockStock(0);
                skuStock.setStatus(status);
                skuStocks.add(skuStock);
            }
        }
    }

    @Override
    public void batchUpdateSkuWarning(List<Sku> skuList) {
        skuMapper.batchUpdateSkuWarning(skuList);
    }


    @Override
    public SkuVO calculateStockBySkuIds(List<SkuComboVO> skuComboList) {
        skuComboList.forEach(skuComboVO -> skuComboVO.setComboSkuId(skuComboVO.getSkuId()));
        List<Long> comboSkuIds = skuComboList.stream().map(SkuComboVO::getComboSkuId).toList();
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(new ArrayList<>(comboSkuIds));
        Map<String, SkuStockVO> comboskuStockMap = skuStockService.mapSkuPointStockByStockPoints(stockPointList);
        Map<Long, List<StockPointSkuVO>> skuStockPointMap = stockPointList.stream().collect(Collectors.groupingBy(StockPointSkuVO::getStockPointId));
        // 获取共同库存数量
        int stock = getMinStockPoint(skuStockPointMap, skuComboList, comboskuStockMap);

        Map<Long, Integer> pointStockMap = new HashMap<>(skuStockPointMap.size());
        int commonStock = 0;
        // 根据仓库id循环判断
        for (Map.Entry<Long, List<StockPointSkuVO>> entry : skuStockPointMap.entrySet()) {
            // 当前区域的sku库存信息列表
            List<StockPointSkuVO> stockPoints = entry.getValue();
            // 如果当前仓库的所有sku库存为空,或者小于需要查询的sku的数量,表示这些关联的sku没有共同库存跳过即可
            if (stockPoints.size() < comboSkuIds.size()) {
                continue;
            }
            for (StockPointSkuVO stockPointSkuVO : stockPoints) {
                SkuStockVO skuStockVO = comboskuStockMap.get(StockUtil.skuPointKey(stockPointSkuVO.getSkuId(), stockPointSkuVO.getStockPointId()));
                int pointStock = skuStockVO.getStock();
                // 组合商品的库存取最小值,比如都是默认仓库的情况下,取最小值
                if (!pointStockMap.containsKey(skuStockVO.getStockPointId()) || pointStockMap.get(skuStockVO.getStockPointId()) > pointStock) {
                    pointStockMap.put(skuStockVO.getStockPointId(), pointStock);
                }
            }
        }

        // 累加上sku的所有组合商品的所有仓库的库存最小值,就是当前sku可用的最小库存
        for (Long pointId : pointStockMap.keySet()) {
            commonStock += pointStockMap.get(pointId);
        }
        SkuVO skuVO = new SkuVO();
        skuVO.setStocks(stock);
        skuVO.setHasCommonStock(commonStock > 0);
        return skuVO;
    }

    @Override
    public void setSkuStock(List<Sku> skus) {
        if (CollectionUtil.isEmpty(skus)) {
            return;
        }
        List<Long> skuIds = skus.stream().map(Sku::getSkuId).collect(Collectors.toList());
        Map<Long, SkuStockVO> skuStockMap = stockManager.mapSkuTotalStock(skuIds);
        List<StockPointSkuVO> pointSkuVOS = stockPointSkuService.listBySkuIds(skuIds);
        Map<String, SkuStockVO> pointStockMap = skuStockService.mapSkuTotalStockAndPointStock(pointSkuVOS);
        Map<Long, List<StockPointSkuVO>> pointMap = pointSkuVOS.stream().collect(Collectors.groupingBy(StockPointSkuVO::getSkuId));
        List<Sku> comboSkuList = Lists.newArrayList();
        for (Sku sku : skus) {
            if (!skuStockMap.containsKey(sku.getSkuId())) {
                sku.setStocks(0);
                sku.setSaleNum(0);
                continue;
            }
            // 补充sku关联仓库库存数据
            if (pointMap.containsKey(sku.getSkuId())) {
                List<StockPointSkuVO> pointList = pointMap.get(sku.getSkuId());
                pointList = pointList.stream().filter(stockPointSkuVO -> Objects.nonNull(stockPointSkuVO.getStockPointSkuId()) && stockPointSkuVO.getStockPointId() != 0).collect(Collectors.toList());
                for (StockPointSkuVO pointSkuVO : pointList) {
                    SkuStockVO skuStockVO = pointStockMap.get(StockUtil.skuPointKey(pointSkuVO.getSkuId(), pointSkuVO.getStockPointId()));
                    pointSkuVO.setStock(Objects.nonNull(skuStockVO) ? skuStockVO.getStock() : 0);
                }
                sku.setStockPointList(BeanUtil.mapAsList(pointList, StockPointSkuDTO.class));
            }
            SkuStockVO skuStockVO = skuStockMap.get(sku.getSkuId());
            sku.setStocks(skuStockVO.getStock());
            sku.setSaleNum(skuStockVO.getSale());
            if (Objects.equals(sku.getMold(), ProdMoldEnum.COMBO.value())) {
                comboSkuList.add(sku);
            }
        }
        // 没有组合sku，库存和销量的查询就结束了
        if (CollUtil.isEmpty(comboSkuList)) {
            return;
        }
        // ============================== 开始统计组合sku的库存数量 ==================================
        List<Long> comboSkuIds = comboSkuList.stream().map(Sku::getSkuId).toList();
        List<SkuComboVO> skuComboVOList = skuComboService.listSkuComboVOBySkuIds(comboSkuIds);
        Map<Long, List<SkuComboVO>> comboSkuMap = skuComboVOList.stream().collect(Collectors.groupingBy(SkuComboVO::getSkuId));
        Set<Long> comboSkuIdSet = new HashSet<>(skuComboVOList.size());
        for (Sku sku : comboSkuList) {
            sku.setSkuComboList(comboSkuMap.get(sku.getSkuId()));
            if (CollectionUtil.isNotEmpty(sku.getSkuComboList())) {
                comboSkuIdSet.addAll(sku.getSkuComboList().stream().map(SkuComboVO::getComboSkuId).toList());
            }
        }
        handleComboSkuStock(comboSkuIdSet, comboSkuList);
    }

    @Override
    public Map<Long, SkuStockVO> mapProdStock(List<Long> prodIds) {
        List<Sku> skus = skuMapper.listSkuAndComboByProdIds(prodIds);
        List<Long> skuIds = skus.stream().map(Sku::getSkuId).toList();
        Map<Long, SkuStockVO> skuStockMap = stockManager.mapSkuTotalStock(skuIds);
        Map<Long, List<Sku>> skuMap = skus.stream().collect(Collectors.groupingBy(Sku::getProdId));
        Map<Long, SkuStockVO> prodStockMap = new HashMap<>();
        List<Sku> comboSkuList = new ArrayList<>();
        Set<Long> comboProdIdSet = new HashSet<>();
        Set<Long> comboSkuIdSet = new HashSet<>();
        for (Long prodId : prodIds) {
            int stock = 0;
            int sale = 0;
            List<Sku> skuList = skuMap.get(prodId);
            if (CollUtil.isEmpty(skuList)) {
                log.info("skuList is null, prodId: {}", prodId);
            } else {
                for (Sku sku : skuList) {
                    SkuStockVO skuStockVO = skuStockMap.get(sku.getSkuId());
                    stock += skuStockVO.getStock();
                    sale += skuStockVO.getSale();
                    if (CollUtil.isNotEmpty(sku.getSkuComboList())) {
                        comboSkuList.add(sku);
                        comboProdIdSet.add(prodId);
                        comboSkuIdSet.addAll(sku.getSkuComboList().stream().map(SkuComboVO::getComboSkuId).toList());
                    }
                }
            }
            SkuStockVO skuStockVO = new SkuStockVO();
            skuStockVO.setStock(stock);
            skuStockVO.setSale(sale);
            prodStockMap.put(prodId, skuStockVO);
        }
        // 没有组合商品，商品库存和销量的统计到此结束
        if (CollUtil.isEmpty(comboSkuList)) {
            return prodStockMap;
        }
        // ============================== 开始统计组合商品的库存数量 ==================================
        handleComboSkuStock(comboSkuIdSet, comboSkuList);
        // 统计组合商品的实际库存
        for (Long prodId : comboProdIdSet) {
            int stock = 0;
            SkuStockVO skuStockVO = prodStockMap.get(prodId);
            List<Sku> skuList = skuMap.get(prodId);
            for (Sku sku : skuList) {
                // 关联的组合商品为空时,此时库存也为空
                stock += Objects.isNull(sku.getStocks()) ? 0 : sku.getStocks();
            }
            skuStockVO.setStock(stock);
        }

        return prodStockMap;
    }


    private void handleComboSkuStock(Set<Long> comboSkuIdSet, List<Sku> skuList) {
        skuList.forEach(sku -> sku.setStocks(0));
        if (CollectionUtil.isEmpty(comboSkuIdSet)) {
            return;
        }
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(new ArrayList<>(comboSkuIdSet));
        Map<String, SkuStockVO> comboskuStockMap = skuStockService.mapSkuPointStockByStockPoints(stockPointList);
        // 计算每个组合sku的库存数量
        for (Sku sku : skuList) {
            if (CollectionUtil.isEmpty(sku.getSkuComboList())) {
                continue;
            }
            List<Long> comboSkuIds = sku.getSkuComboList().stream().map(SkuComboVO::getComboSkuId).toList();
            List<StockPointSkuVO> skuStockPointList = stockPointList.stream().filter(stockPointSkuVO -> comboSkuIds.contains(stockPointSkuVO.getSkuId())).toList();
            Map<Long, List<StockPointSkuVO>> skuStockPointMap = skuStockPointList.stream()
                    .collect(Collectors.groupingBy(StockPointSkuVO::getStockPointId));
            // 获取组合sku的库存
            int stock = getMinStockPoint(skuStockPointMap, sku.getSkuComboList(), comboskuStockMap);
            sku.setStocks(stock);
            sku.setSkuComboList(null);
        }
    }

    private static int getMinStockPoint(Map<Long, List<StockPointSkuVO>> skuStockPointMap, List<SkuComboVO> comboList, Map<String, SkuStockVO> comboskuStockMap) {
        Map<Long, Integer> pointStockMap = new HashMap<>(skuStockPointMap.size());
        int stock = 0;
        // 根据仓库id循环判断
        for (Map.Entry<Long, List<StockPointSkuVO>> entry : skuStockPointMap.entrySet()) {
            // 当前区域的sku库存信息列表
            List<StockPointSkuVO> stockPoints = entry.getValue();
            // 如果当前仓库的所有sku库存为空,或者小于需要查询的sku的数量,表示这些关联的sku没有共同库存跳过即可
            if (stockPoints.size() < comboList.size()) {
                continue;
            }
            Map<Long, StockPointSkuVO> comboSkuPoinStockMap = stockPoints.stream().collect(Collectors.toMap(StockPointSkuVO::getSkuId, Function.identity()));
            for (SkuComboVO skuComboVO : comboList) {
                StockPointSkuVO stockPointSkuVO = comboSkuPoinStockMap.get(skuComboVO.getComboSkuId());
                if (Objects.isNull(stockPointSkuVO)) {
                    continue;
                }
                // 计算sku中每个单品的库存数量
                // 获取单品的区域库存信息
                SkuStockVO skuStockVO = comboskuStockMap.get(StockUtil.skuPointKey(skuComboVO.getComboSkuId(), stockPointSkuVO.getStockPointId()));
                // 组合sku中单品实际库存数量 = 单品库存数量 / 单品组合数量
                // 除以组合数量向下取整得出 当前的组合商品-当前仓库 可用库存
                int pointStock = Math.floorDiv(skuStockVO.getStock(), skuComboVO.getComboCount());
                // 如果是0就是总库存,直接跳过
                if (Objects.equals(stockPointSkuVO.getStockPointId(), StockManager.WAREHOUSE_ID)) {
                    continue;
                }
                // 组合商品的库存取最小值,比如都是默认仓库的情况下,取最小值
                if (!pointStockMap.containsKey(stockPointSkuVO.getStockPointId()) || pointStockMap.get(stockPointSkuVO.getStockPointId()) > pointStock) {
                    pointStockMap.put(stockPointSkuVO.getStockPointId(), pointStock);
                }
            }
        }

        // 累加上sku的所有组合商品的所有仓库的库存最小值,就是当前sku可用的最小库存
        for (Long pointId : pointStockMap.keySet()) {
            stock += pointStockMap.get(pointId);
        }
        return stock;
    }

    public IPage<Sku> pageGoodsSourceStatusSku(PageParam<Sku> page, Integer goodsSourceStatus) {
        return skuMapper.pageGoodsSourceStatusSku(page, goodsSourceStatus);
    }


    public void updateGoodSourceStatus(Integer goodsSourceStatus, Long skuId) {
        skuMapper.updateGoodSourceStatus(goodsSourceStatus, skuId);
    }

}
